<?php

namespace App\Services;

use App\Models\MoneyTransfer;
use App\Models\Partner;
use App\Models\PartnerConfig;
use App\Models\PartnerUser;
use common\enum\MoneyTransferEnum;
use common\utils\PartnerSDK;
use common\utils\RedisKeys;
use common\utils\SysCode;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Request;
use services\CommonAPIService;

class MoneyTransferService
{
    const EXCEPTION_HANDLE_TYPE = [
        //1 支持订单号查询 (或者会员+时间段查询)  (补单操作自动判断返回订单号查询， 还是时间段查询结果)
        //2 手动补单
        'FG' => 2,
        'AG' => 1,      //时间范围
        'HB' => 1,      //订单号查询    时间范围查询
        'MW' => 1,      //订单号查询
        'OG' => 1,      //订单号查询    时间范围查询
        'MG' => 1,      //订单号查询    时间范围查询
        'CQ9' => 1,     //订单号查询    时间范围查询
        'GNS' => 1,     //订单号查询    时间范围查询
        'SB' => 1,      //订单号查询
        'HC' => 1,      //订单号查询
        'BG' => 1,      //时间范围查询
        'KY' => 2,
        'LEG' => 2,
        'SG' => 1,      //订单号查询
        'EBET' => 1,    //时间范围查询 白名单限制？？
        'LEBO' => 2,
        'BNG' => 1,     //时间范围查询
        'SBTECH' => 2,
    ];

    /**
     * 转账记录
     * @param array $params
     * @return array
     * @throws \App\Exceptions\CustomException
     * @throws \common\exception\CustomException
     */
    public static function getTransferList($params = [])
    {
        $page = isset($params['page']) ? $params['page'] : 1;
        $size = isset($params['page_size']) ? $params['page_size'] : 20;
        $startTime = isset($params['time_begin']) ? date('Y-m-d 00:00:00', strtotime("{$params['time_begin']}")) : null;
        $endTime = isset($params['time_end']) ? date('Y-m-d 23:59:59', strtotime("{$params['time_end']}")) : null;
        $isException = (isset($params['exception']) && $params['exception'] == 1) ? true : false;//是否转账异常列表
        // 判断转入转出钱包类型
        if (isset($params['in_id']) && isset($params['out_id'])) {
            //过滤掉主转主，子转子
            if (($params['in_id'] == 0 && $params['out_id'] == 0)) {
                error_exit(SysCode::TRANSFER_SEARCH_INVALID_MAIN_TYPE);
            }
            if ($params['in_id'] != 0 && $params['out_id'] != 0) {
                error_exit(SysCode::TRANSFER_SEARCH_INVALID_PATNER_TYPE);
            }
        }
        if (isset($params['in_id'])) {
            if ($params['in_id'] == 0) {
                $params['type'] = MoneyTransferEnum::TRANSFER_TYPE_PARTNER2MAIN;//子转主
            } else {
                $params['money_partner_id'] = $params['in_id'];
                $params['type'] = MoneyTransferEnum::TRANSFER_TYPE_MAIN2PARTNER;//主转子
            }
        } elseif (isset($params['out_id'])) {
            if ($params['out_id'] == 0) {
                $params['type'] = MoneyTransferEnum::TRANSFER_TYPE_MAIN2PARTNER;//主转子
            } else {
                $params['money_partner_id'] = $params['out_id'];
                $params['type'] = MoneyTransferEnum::TRANSFER_TYPE_PARTNER2MAIN;//子转主
            }
        }

        $query = DB::table('money_transfer as t')->leftJoin('hall as h', 'h.id', '=', 't.hall_id')
            ->select([
                't.id',
                't.user_id',
                't.username',
                't.money_partner_id',
                't.money_partner_name',
                't.type',
                't.amount',
                't.order_number',
                't.partner_order_number',
                't.operater_admin_id',
                't.status',
                't.remark',
                't.created_at',
                't.updated_at',
                'h.company_name',
            ]);
        //是否转账异常列表
        if ($isException) {
            $query->where('t.status', '=', MoneyTransferEnum::TRANSFER_STATUS_EXCEPTION);
        } else {
            if (isset($params['status'])) {
                //状态， 支持查询 0为pendding，1为成功，2为失败 100 异常订单
                $query->where('t.status', '=', (int)$params['status']);
            } else {
                $query->where('t.status', '<>', MoneyTransferEnum::TRANSFER_STATUS_EXCEPTION);
            }
        }

        //厅主筛选
        if (!empty($params['hall_id'])) {
            $query->where('t.hall_id', '=', $params['hall_id']);
        }
        //时间筛选
        if (!empty($startTime)) {
            $query->where('t.created_at', '>=', $startTime);
        }
        if (!empty($endTime)) {
            $query->where('t.created_at', '<=', $endTime);
        }
        if ($params) {
            foreach ($params as $k => $v) {
                if ($k == 'username' && !empty(trim($v))) {
                    $query->where('t.username', 'like', "%{$v}%");
                }
                //子钱包
                if (($k == 'out_id' || $k == 'in_id') && $v) {
                    $query->where('t.money_partner_id', '=', $v);
                }
                if ($k == 'type') {
                    $query->where('t.type', '=', $params['type']);
                }
            }
        }


        //转账金额范围
        if (isset($params['amount_from'])) {
            $query->whereRaw('abs(t.amount) >= ' . $params['amount_from']);
        }
        if (isset($params['amount_to'])) {
            $query->whereRaw('abs(t.amount) <= ' . $params['amount_to']);
        }
        $query->orderBy('t.created_at', 'desc');

        //获取分页
        $result = get_page_data($query, $page, $size);
        if (!empty($result['list'])) {
            foreach ($result['list'] as &$datum) {
                $datum = (array)$datum;
                $datum['amount'] = abs($datum['amount']);
                if ($datum['type'] == MoneyTransferEnum::TRANSFER_TYPE_MAIN2PARTNER) {
                    $datum['out_type'] = '主钱包';
                    $datum['in_type'] = $datum['money_partner_name'] . '子钱包';
                }
                if ($datum['type'] == MoneyTransferEnum::TRANSFER_TYPE_PARTNER2MAIN) {
                    $datum['out_type'] = $datum['money_partner_name'] . '子钱包';
                    $datum['in_type'] = '主钱包';
                }

                //状态
                $datum['status_des'] = MoneyTransferEnum::TRANSFER_STATUS_DES[$datum['status']] ?? '未知状态';

                //异常单处理类型
                $datum['handle_type'] = static::EXCEPTION_HANDLE_TYPE[$datum['money_partner_name']] ?? 2;//默认手动处理
            }
        }
        return $result;

    }

    /**
     * 手动处理转账异常单  修改成功或失败
     * @param $params
     */
    public static function handle($params)
    {
        if (empty($params['id']) || !in_array($params['status'], [
                MoneyTransferEnum::TRANSFER_STATUS_SUCCESS,
                MoneyTransferEnum::TRANSFER_STATUS_FAILED
            ])) {//只允许改为成功  或者 失败
            error_exit(SysCode::TRANSFER_INVALID_PARAMS);
        }
        $ret = app('commonSDK')->handleTransfer($params['id'], $params['status'], $params['remark'] ?? '');
        if (empty($ret) || !isset($ret['code'])) {
            error_exit(SysCode::FAILED, '请求失败,请稍后再试');
        }
        if ($ret['code'] == SysCode::OK) {
            return [];
        } else {
            error_exit($ret['code'], $ret['msg'] ?? '处理失败');
        }
    }

    /**
     * 补单检测结果
     * @param $id
     */
    public static function getTransferSupplement($id)
    {
        if (empty($id)) {
            error_exit(SysCode::TRANSFER_INVALID_PARAMS);
        }

        $moneyTransferInfo = MoneyTransfer::where(['id' => $id])->first();
        if (!$moneyTransferInfo) {
            error_exit(SysCode::TRANSFER_ORDER_NOT_FOUND);
        }
        //已成功的订单， 不需要处理
        if ($moneyTransferInfo['status'] == MoneyTransferEnum::TRANSFER_STATUS_SUCCESS) {
            error_exit(SysCode::TRANSFER_SUPPLEMENT_SUCC_CANT_SUPPLEMENT);
        }

        //统一返回结果规则
        $result = [
            'info' => $moneyTransferInfo->toArray(),//转账信息
            'result_type' => 0,//1 订单号查询，返回转账成功或失败状态  2 时间返回查询， 返回5分钟内多笔订单（第三方和平台的都需要）
            'status' => null,//鉴定的转账状态， 只有根据订单号查询需要使用
            'api_order_list' => [],//第三方5分钟内多笔订单
            'platform_order_list' => [],//平台5分钟内多笔订单
            'result_des' => '',//结果说明
        ];

        $partnerName = $moneyTransferInfo['money_partner_name'];
        $partnerUserName = static::getPartnerUsername($moneyTransferInfo['user_id'],
            $moneyTransferInfo['money_partner_name']);
        $orderNumber = $moneyTransferInfo['order_number'];
        $beginTime = strtotime($moneyTransferInfo['created_at']);

        $returnMeg = null;
        //首先根据转账单号查询
        try {
            $result['result_type'] = 1;
            $ret = app('partnerSDK')->checkTransferResult($partnerName, $partnerUserName, $orderNumber, $beginTime);
            if (isset($ret['code'])) {
                if ($ret['code'] == SysCode::OK) {//转账成功
                    $result['status'] = MoneyTransferEnum::TRANSFER_STATUS_SUCCESS;
                    $result['result_des'] = static::getResultDes($moneyTransferInfo,
                        MoneyTransferEnum::TRANSFER_STATUS_SUCCESS);
                    return $result;
                } elseif ($ret['code'] == SysCode::API_ERROR_TRANSFER_FAILED) {//转账失败
                    $result['status'] = MoneyTransferEnum::TRANSFER_STATUS_FAILED;
                    $result['result_des'] = static::getResultDes($moneyTransferInfo,
                        MoneyTransferEnum::TRANSFER_STATUS_FAILED);
                    return $result;
                } else {//其它错误状态忽略， 继续执行时间范围查询
                    $returnMeg = $ret['msg'] ?? null;
                }
            }
        } catch (\Throwable $e) {
            if ($e->getCode() != SysCode::API_ERROR_METHOD_UNCOMPLETE) {//方法未实现
                $returnMeg = $e->getMessage();
            }
            //其它错误状态忽略， 继续执行时间范围查询
//            return $e->getTraceAsString();
        }

        //没有则根据会员+时间范围查询
        $result['platform_order_list'] = static::getPlatformOrderList($beginTime, $partnerName);
        try {
            $result['result_type'] = 2;
            $result['result_des'] = '5分钟内第三方与平台多笔订单可供参考， 可以登录第三方后台进行二次确认转账订单， 有问题请联系技术人员';
//            if($partnerName == 'AG'){
//                $partnerUserName = 'ag';
//                $beginTime = strtotime('2018-12-22 04:47:40');
//            }
//            if($partnerName == 'BG'){
//                $partnerUserName = 'test_bg_100_23';
//                $beginTime = strtotime('2018-12-14 04:25:02');
//            }
            $ret = app('partnerSDK')->getTransferResult($partnerName, $partnerUserName, $beginTime);
            if ($ret['code'] == SysCode::OK) {//获取列表成功
                /**
                 * {
                 *     partner_order_number : '',//第三方訂單號（需要增加）
                 *     username:"",//第三方用户名
                 *     balance:"",//当前余额（单位厘）
                 *     amount:"",//转账金额（单位厘，正数）
                 *     type:"",//1:子钱包加钱，2:子钱包减钱
                 *     status:"",//1:成功, 2:失败, 3:其他
                 *     created_at:"",//转账发生时间
                 * }
                 */
                $apiOrderList = $ret['data'];
                foreach ($apiOrderList as & $val) {
                    $val['status_des'] = MoneyTransferEnum::TRANSFER_STATUS_DES[$val['status']] ?? $val['status'];
                    $val['partner_order_number'] = $val['partner_order_number'] ?? '';//第三方订单号
                }
                $result['api_order_list'] = $apiOrderList;
                return $result;
            } else {//获取列表失败， 暂不处理
                $returnMeg = $ret['msg'] ?? null;
            }

        } catch (\Throwable $e) {
            if ($e->getCode() != SysCode::API_ERROR_METHOD_UNCOMPLETE) {//方法未实现
                $returnMeg = $e->getMessage();
            }
            //其它错误状态忽略， 继续执行时间范围查询
//            return $e->getTraceAsString();
        }

        //最后返回失败
        return $returnMeg ? error_exit(SysCode::TRANSFER_SUPPLEMENT_FAIL,
            $returnMeg) : error_exit(SysCode::TRANSFER_SUPPLEMENT_FAIL);
    }

    // 获取第三方游戏用户名
    public static function getPartnerUsername($userId, $partnerName)
    {
        $pu = PartnerUser::where([
            'user_id' => $userId,
            'partner_name' => strtoupper($partnerName),
        ])->first();
        if ($pu) {
            return $pu->partner_username;
        }
        return null;
    }

    /**
     * 获取结果说明
     * @param $moneyTransferInfo
     * @param $status
     */
    public static function getResultDes($moneyTransferInfo, $status)
    {
        $type = $moneyTransferInfo['type'];
        $des = '未知状态， 请联系技术';
        if ($type == MoneyTransferEnum::TRANSFER_TYPE_MAIN2PARTNER) {//主转子
            if ($status == MoneyTransferEnum::TRANSFER_STATUS_SUCCESS) {
                $des = sprintf("%s子钱包已同步转账金额，更新订单状态", $moneyTransferInfo['money_partner_name']);
            } elseif ($status == MoneyTransferEnum::TRANSFER_STATUS_FAILED) {
                $des = sprintf("%s子钱包未同步到转账金额，系统将转账金额退换主钱包，并更新订单状态", $moneyTransferInfo['money_partner_name']);
            }
        } else {
            if ($status == MoneyTransferEnum::TRANSFER_STATUS_SUCCESS) {
                $des = sprintf("%s子钱包成功转出金额，系统将补增主钱包金额, 并更新订单状态", $moneyTransferInfo['money_partner_name']);
            } elseif ($status == MoneyTransferEnum::TRANSFER_STATUS_FAILED) {
                $des = sprintf("%s子钱包未成功转出金额，更新订单状态", $moneyTransferInfo['money_partner_name']);
            }
        }
        return $des;
    }

    /**
     * 获取平台转账订单 5分钟内
     * @param $beginTime  timestamp
     * @return array
     */
    public static function getPlatformOrderList($beginTime, $partnerName)
    {
        $startTime = date('Y-m-d H:i:s', $beginTime - 5 * 60);
        $endTime = date('Y-m-d H:i:s', $beginTime + 5 * 60);
        $data = MoneyTransfer::select(['order_number', 'created_at', 'amount', 'status'])
            ->where('money_partner_name', '=', $partnerName)
            ->where('created_at', '>=', $startTime)
            ->where('created_at', '<=', $endTime)
            ->get();
        if (!$data) {
            return [];
        }
        $data = $data->toArray();
        foreach ($data as & $val) {
            $val['status_des'] = MoneyTransferEnum::TRANSFER_STATUS_DES[$val['status']] ?? $val['status'];
            $val['amount'] = abs($val['amount']);
        }
        return $data;
    }

    /**
     * 获取转账异常告警订单数
     * 需求说明：
     * 1.点击消息跳转到转账异常模块
     *
     * 2.当有超过20秒转账订单还是异常的订单，需要做消息预警
     *
     * 3.提示方式：如果有新的预警每隔30秒进行预警提醒
     * @return int
     */
    public static function exceptionNum()
    {
        $redis = Redis::connection();
        $lastWarningTimeKey = RedisKeys::TRANSFER_EXCEPTION_WARNING_TIME;

        $lastWarningTime = $redis->get($lastWarningTimeKey);
        $lastWarningTime = $lastWarningTime ? $lastWarningTime : '2018-01-01';

        $endTime = date('Y-m-d H:i:s', time() - 20);//本次获取结束时间

        //获取上次告警以后， 是否存在新的异常单
        $existsWarning = MoneyTransfer::where('status', '=',
            MoneyTransferEnum::TRANSFER_STATUS_EXCEPTION)->where('created_at', '>',
            $lastWarningTime)->where('created_at', '<', $endTime)->first();
        $nowNum = MoneyTransfer::where('status', '=', MoneyTransferEnum::TRANSFER_STATUS_EXCEPTION)->where('created_at',
            '<', $endTime)->get()->count();

        //如果存在新的异常告警， 则更新告警时间
        if ($existsWarning) {
            $redis->set($lastWarningTimeKey, $endTime);
        }

        return [
            'num' => (int)$nowNum,     //当前异常单数量
            'warning' => $existsWarning ? 1 : 0,//1 前端告警提示
        ];
    }

    /**
     * 获取额度转账钱包列表， 主钱包id=0
     * @return mixed
     */
    public static function getWalletList()
    {
        $data = PartnerConfig::select('partner_id', 'partner_name')->groupBy('partner_id')->get()->toArray();
        array_unshift($data, ['partner_id' => 0, 'partner_name' => '主钱包']);
        return $data;
    }
}